package com.bflow.impl.example;

import com.bflow.api.IBflowDefineProcessService;
import com.bflow.api.IBflowExtResService;
import com.bflow.api.IDefaultAuditTemplateService;
import com.bflow.api.bo.*;
import com.bflow.api.bo.example.ExampleLeaveBo;
import com.bflow.api.constant.BflowConstant;
import com.bflow.api.constant.BflowConstant.DefActKey;
import com.bflow.api.constant.example.leave.ExampleLeaveConstant.LeaveType;
import com.bflow.api.example.IExampleLeaveService;
import com.bflow.commons.bean.PageResult;
import com.bflow.commons.exception.BizException;
import com.bflow.commons.util.StrUtil;
import com.bflow.util.AssertUtil;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;

import static com.bflow.api.constant.BflowConstant.ACT_SPLIT;
import static com.bflow.api.constant.BflowConstant.UNDERLINE;

/**
 * 功能：ExampleLeaveServiceImpl 示例请假流程-实现业务接口
 * 作者：liaofeng
 * 日期：2018-12-19
 */
@Service("exampleLeaveService")
public class ExampleLeaveServiceImpl implements IExampleLeaveService {

    @Autowired
    private IDefaultAuditTemplateService defaultAuditTemplateService;

    @Autowired
    private IBflowExtResService bflowExtResService;

    @Autowired
    private IBflowDefineProcessService<?, BflowDefineProcessBo> iBflowDefineProcessService;

    private final Logger logger = LoggerFactory.getLogger(ExampleLeaveServiceImpl.class);

    /**
     * 查询历史记录列表
     *
     * @param queryParam
     * @return
     * @throws BizException
     */
    @Override
    public PageResult<BflowRunInstanceBo> findHistoryList(BflowRunInstanceQueryParam queryParam) throws BizException {
        PageResult<BflowRunInstanceBo> pageResult = defaultAuditTemplateService.findHistoryList(queryParam, BflowConstant.ProcessBusiKeyType.LEAVEAPPLY.getCode());
        List<BflowRunInstanceBo> dataList = pageResult.getResult();
        this.packHistoryList(dataList);
        pageResult.setResult(dataList);
        return pageResult;
    }

    /**
     * 包装请假历史列表数据
     *
     * @param dataList
     */
    private void packHistoryList(List<BflowRunInstanceBo> dataList) {
        if (CollectionUtils.isNotEmpty(dataList)) {
            for (BflowRunInstanceBo instanceBo : dataList) {
                this.packBizInfo(instanceBo, null, false, null);
            }
        }
    }

    /**
     * 包装请假业务信息
     *
     * @param instanceBo
     * @return
     */
    private BflowRunInstanceBo packBizInfo(BflowRunInstanceBo instanceBo, BflowDefineProcessBo processBo, Boolean isFindCopyToUser, String loginUserId) {
        if (instanceBo != null) {
            LeaveType leaveType = LeaveType.get(instanceBo.getExtBigint1().intValue());
            if (leaveType != null)
                instanceBo.setExtVarchar2(leaveType.getTitle());

            BflowConstant.FlowRunInstanceStatus status = BflowConstant.FlowRunInstanceStatus.get(instanceBo.getStatus());
            if (status != null)
                instanceBo.setStatusName(status.getTitle());

            instanceBo.setStartURoleName(bflowExtResService.getUserRoleName(instanceBo.getStartUid()));

            if(isFindCopyToUser){
                String copyToUserIds = null;
                if(processBo != null){
                    copyToUserIds = processBo.getCopyTo();

                }else if(StringUtils.isNotBlank(instanceBo.getProcKey())){
                    String procId = instanceBo.getProcKey().substring(instanceBo.getProcKey().indexOf(BflowConstant.PROCESS_KEY_TPL_PREFIX) + BflowConstant.PROCESS_KEY_TPL_PREFIX.length());
                    if(StringUtils.isNotBlank(procId)){
                        processBo = iBflowDefineProcessService.findById(procId);
                        if(processBo != null){
                            copyToUserIds = processBo.getCopyTo();
                        }
                    }
                }

                if(StringUtils.isNotBlank(copyToUserIds)){
                    String[] copyToUserIdArray = copyToUserIds.split(ACT_SPLIT);
                    if(ArrayUtils.isNotEmpty(copyToUserIdArray)){
                        StringBuilder copyToUserName = new StringBuilder();
                        for (String copyToUserId : copyToUserIdArray){
                            if(StringUtils.isNotBlank(copyToUserId)){
                                String userId = copyToUserId.replaceAll(UNDERLINE,"");
                                if(StringUtils.isNotBlank(userId)){
                                    String userName = loginUserId!=null?userId.equals(loginUserId)?"我":bflowExtResService.getUserName(userId):bflowExtResService.getUserName(userId);
                                    if(StringUtils.isNotBlank(userName)){
                                        copyToUserName.append(userName + ACT_SPLIT);
                                    }
                                }
                            }
                        }

                        if(StringUtils.isNotBlank(copyToUserName.toString())){
                            instanceBo.setCopyToUserName(copyToUserName.toString().substring(0, copyToUserName.toString().lastIndexOf(ACT_SPLIT)));
                        }
                    }
                }
            }
        }
        return instanceBo;
    }

    /**
     * 查询审批列表
     *
     * @param queryParam
     * @param userKey    用户key
     * @return
     * @throws BizException
     */
    @Override
    public PageResult<BflowRunTaskBo> findAuditList(BflowRunTaskQueryParam queryParam, String userKey) throws BizException {
        PageResult<BflowRunTaskBo> pageResult = defaultAuditTemplateService.findAuditList(queryParam, userKey, BflowConstant.ProcessBusiKeyType.LEAVEAPPLY.getCode());
        List<BflowRunTaskBo> dataList = pageResult.getResult();
        this.packAuditList(dataList, userKey);
        pageResult.setResult(dataList);
        return pageResult;
    }

    /**
     * 包装请假审批列表数据
     *
     * @param dataList
     * @param userId
     */
    private void packAuditList(List<BflowRunTaskBo> dataList, String userId) {
        if (CollectionUtils.isNotEmpty(dataList)) {
            for (BflowRunTaskBo taskBo : dataList) {
                this.packRunTaskBizInfo(taskBo, userId);
            }
        }
    }

    /**
     * 包装请假业务信息
     *
     * @param taskBo
     * @param userId
     */
    private void packRunTaskBizInfo(BflowRunTaskBo taskBo, String userId) {
        if (taskBo != null) {
            BflowRunInstanceBo instanceBo = this.packBizInfo(taskBo.getInstance(), null, false, null);
            taskBo.setInstance(instanceBo);
        }
    }

    /**
     * 提交请假申请
     *
     * @param leaveBo
     * @throws BizException
     */
    @Transactional
    @Override
    public void addLeave(ExampleLeaveBo leaveBo) throws BizException {
        //校验参数
        this.validLeaveApplyInfo(leaveBo);
        //设置业务数据
        BflowRunInstanceBo instanceBo = setInstanceData(leaveBo);
        //设置定义流程数据
        BflowDefineProcessBo defineProcessBo = setProcessData(leaveBo);
        defaultAuditTemplateService.addApply(instanceBo, leaveBo.getAuditUserIds(), DefActKey.DEF_USER_AUDIT.getCode(), defineProcessBo);
    }

    /**
     * 设置业务数据
     *
     * @param leaveBo
     * @return
     */
    private BflowRunInstanceBo setInstanceData(ExampleLeaveBo leaveBo) {
        //设置业务数据
        BflowRunInstanceBo instanceBo = new BflowRunInstanceBo();
        instanceBo.setBusiId(leaveBo.getApplyUid());
        instanceBo.setStartUid(leaveBo.getApplyUid());
        instanceBo.setStartUname(leaveBo.getApplyUname());
        instanceBo.setExtBigint1(leaveBo.getType().longValue());     //请假类型
        instanceBo.setExtDatetime1(leaveBo.getBeginTime());     //开始时间
        instanceBo.setExtDatetime2(leaveBo.getEndTime());     //结束时间
        instanceBo.setExtNumeric1(leaveBo.getLeaveDay());     //请假天数
        instanceBo.setExtVarchar1(leaveBo.getReason());     //请假事由

        return instanceBo;
    }

    /**
     * 设置定义流程数据
      * @param leaveBo
     * @return
     */
    private BflowDefineProcessBo setProcessData(ExampleLeaveBo leaveBo) {
        //设置业务数据
        BflowDefineProcessBo defineProcessBo = new BflowDefineProcessBo();
        defineProcessBo.setKey(BflowConstant.ProcessBusiKeyType.LEAVEAPPLY.getCode());
        defineProcessBo.setName(leaveBo.getApplyUname() + "_" + BflowConstant.ProcessBusiKeyType.LEAVEAPPLY.getTitle());
        if(StringUtils.isNotBlank(leaveBo.getCopyToUserIds())){
            String copyToUserIds = leaveBo.getCopyToUserIds();
            String[] copyToUserIdsSet = copyToUserIds.split(ACT_SPLIT);
            if(ArrayUtils.isNotEmpty(copyToUserIdsSet)){
                defineProcessBo.setCopyTo(StrUtil.join(copyToUserIdsSet, ACT_SPLIT));
            }
        }
        defineProcessBo.setCopyToIntervalType(BflowConstant.DefineProcess_CopyToIntervalType.ENDPASS.getCode());

        return defineProcessBo;
    }

    /**
     * 验证请假申请信息
     *
     * @param leaveBo
     */
    private void validLeaveApplyInfo(ExampleLeaveBo leaveBo) {
        AssertUtil.isNotNull(leaveBo, "提交的请假申请内容 不能为空");
        AssertUtil.isNotNull(leaveBo.getType(), "请假类型 不能为空");
        AssertUtil.isNotNull(leaveBo.getBeginTime(), "开始时间 不能为空");
        AssertUtil.isNotNull(leaveBo.getEndTime(), "结束时间 不能为空");
        AssertUtil.isNotNull(leaveBo.getLeaveDay(), "请假天数 不能为空");
        AssertUtil.isNotBlank(leaveBo.getReason(), "请假事由 不能为空");
        AssertUtil.isNotBlank(leaveBo.getAuditUserIds(), "审批人集合 不能为空");
        AssertUtil.isNotBlank(leaveBo.getApplyUid(), "发起人ID 不能为空");
        AssertUtil.isNotBlank(leaveBo.getApplyUname(), "发起人姓名 不能为空");
    }

    /**
     * 审批
     *
     * @param auditBo
     * @throws BizException
     */
    @Transactional
    @Override
    public void audit(BflowRunTaskAuditBo auditBo) throws BizException {
        //验证请假审批信息
        this.validLeaveAuditInfo(auditBo);
        defaultAuditTemplateService.audit(auditBo, DefActKey.DEF_USER_AUDIT.getCode());
    }

    /**
     * 验证请假审批信息
     *
     * @param auditBo 作者：liaofeng
     */
    private void validLeaveAuditInfo(BflowRunTaskAuditBo auditBo) {
        AssertUtil.isNotNull(auditBo, "提交的请假审批内容 不能为空");
        AssertUtil.isNotBlank(auditBo.getTaskId(), "任务ID 不能为空");
        AssertUtil.isNotBlank(auditBo.getOperationUserId(), "操作人ID 不能为空");
        AssertUtil.isNotBlank(auditBo.getRouteId(), "审批结论 不能为空");
        AssertUtil.isNotBlank(auditBo.getRemarks(), "审批意见 不能为空");
    }

    /**
     * 查询instance业务数据
     *
     * @param instanceId
     * @param userId
     * @return
     * @throws BizException
     */
    @Override
    public BflowRunInstanceBo detail(String instanceId, String userId) throws BizException {
        BflowRunInstanceBo instanceBo = defaultAuditTemplateService.detail(instanceId, userId);
        this.packBizInfo(instanceBo, null, true, userId);
        return instanceBo;
    }


    /**
     * 获取task任务数据
     *
     * @param taskId
     * @param userId
     * @return
     * @throws BizException
     */
    @Override
    public BflowRunTaskBo getRunTaskDetail(String taskId, String userId) throws BizException {
        BflowRunTaskBo taskBo = defaultAuditTemplateService.getRunTaskDetail(taskId, userId, DefActKey.DEF_USER_AUDIT.getCode());
        if (taskBo != null) {
            taskBo.setInstance(packBizInfo(taskBo.getInstance(), null, true, userId));
        }
        return taskBo;
    }

    /**
     * 查询我的请假历史记录列表
     *
     * @param queryParam
     * @return
     * @throws BizException
     */
    @Override
    public PageResult<BflowRunInstanceBo> findMyHistoryList(BflowRunInstanceQueryParam queryParam, String userId) throws BizException {
        PageResult<BflowRunInstanceBo> pageResult = defaultAuditTemplateService.findMyHistoryList(queryParam, BflowConstant.ProcessBusiKeyType.LEAVEAPPLY.getCode(), userId);
        List<BflowRunInstanceBo> dataList = pageResult.getResult();
        this.packHistoryList(dataList);
        pageResult.setResult(dataList);
        return pageResult;
    }

    /**
     * 查询抄送给我的请假列表
     * @param queryParam
     * @param userId
     * @return
     * @throws BizException
     */
    @Override
    public PageResult<BflowDefineProcessBo> findCopyToMeList(BflowDefineProcessQueryParam queryParam, String userId) throws BizException {
        PageResult<BflowDefineProcessBo> pageResult = defaultAuditTemplateService.findCopyToList(queryParam, BflowConstant.ProcessBusiKeyType.LEAVEAPPLY.getCode(), BflowConstant.DefineProcess_CopyToIntervalType.ENDPASS.getCode(), userId, BflowConstant.RunInstance_FinalConclusion.PASS.getCode());
        List<BflowDefineProcessBo> dataList = pageResult.getResult();
        this.packCopyToMeList(dataList);
        pageResult.setResult(dataList);
        return pageResult;
    }

    /**
     * 包装抄送给我的请假列表数据
     * @param dataList
     * @return
     */
    private List<BflowDefineProcessBo> packCopyToMeList(List<BflowDefineProcessBo> dataList){
        if(CollectionUtils.isNotEmpty(dataList)){
            for (BflowDefineProcessBo processBo : dataList) {
                if (processBo != null) {
                    BflowRunInstanceBo instanceBo = this.packBizInfo(processBo.getInstance(), processBo, false, null);
                    processBo.setInstance(instanceBo);
                }
            }
        }

        return dataList;
    }

}